using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using OpenComposite.Base.Designer;
using OpenComposite.Repository.Properties;
using OpenComposite.EII.Repository;
using WeifenLuo.WinFormsUI.Docking;

namespace OpenComposite.EII.Designer.SCA
{
	public class ReferenceSymbol : Symbol, IRepositoryItemSymbol
	{
		#region Initialization
		public ReferenceSymbol()
		{
			init();
		}
		private void init()
		{
			this.BeginUpdate();

			this.Border = BorderType.SimpleArrowRight;
			this.BorderColor = Color.Black;
			this.BorderWidth = 2;

			//this.BackColor = Color.FromArgb(204, 153, 255);
			this.BackColor = Color.YellowGreen;
			this.BackColor2 = Color.White;
			this.BackLinearGradientMode = LinearGradientMode.ForwardDiagonal;
			this.BackBrushMode = BackgroundBrushMode.LinearGradient;

			//this.Name = "referenceSymbol" + GetCount(typeof(ReferenceSymbol));
			this.Text = "Reference";
			this.TextAlign = ContentAlignment.MiddleCenter;

			this.Size = new Size(80, 50);
			this.MinimumSize = new Size(70, 50);

			//
			// this.ContextMenuStrip
			//
			this.ContextMenuStrip = new ContextMenuStrip();
			this.ContextMenuStrip.Items.Add("View Operations...", null, new EventHandler(context_EditOperations));
			//this.ContextMenuStrip.Items.Add(new ToolStripSeparator());
			//this.ContextMenuStrip.Items.Add("Remove Reference", Resources.ico_delete_16x.ToBitmap(), new EventHandler(context_Remove));

			_folder = null;
			_isCollapsed = false;
			_interface = null;
			_lstReferenceOperations = new List<OpenComposite.EII.Repository.Operation>();
			_lstRoutes = new List<Route>();

			this.EndUpdate();
		}
		#endregion

		#region Public Members

		#region Properties
		public InterfaceSymbol Interface
		{
			get
			{
				if ( _reference != null )
					return _reference.Interface;
				else
					return _interface;
			}
			set
			{
				if ( _interface != value ) {
					_interface = value;
					_reference = null;
				}
			}
		}
		public List<Repository.Operation> Operations
		{
			get
			{
				//if ( _interface != null )
				//    return _interface.Operations;
				//else if ( _reference != null )
				//    return _reference.Operations;
				//else
				return _lstReferenceOperations;
			}
		}
		#endregion

		#region Events
		public event EventHandler OperationsChanged = null;
		#endregion

		#region Methods
		public void Expand()
		{
			_isCollapsed = false;
			this.NameTextBox.Visible = true;
			this.MinimumSize = new Size(70, 50);
			this.Size = new Size(80, 50);
		}
		public void Collapse()
		{
			_isCollapsed = true;
			this.NameTextBox.Visible = false;
			this.MinimumSize = new Size(25, 15);
			this.Size = new Size(25, 15);
		}
		#endregion

		#region Overrides
		public override bool UseGrid
		{
			get
			{
				return false;// !_isCollapsed;
			}
		}
		public override bool NoClip
		{
			get
			{
				return true;
			}
		}
		public override bool CanMove
		{
			get
			{
				return false;
			}
		}
		public override bool CanResize
		{
			get
			{
				return false;
			}
		}

		public override object GetDragObject(Point location, MouseButtons button)
		{
			return this;
		}
		public override void DropObject(object obj, Point location, MouseButtons button)
		{
			if ( button == MouseButtons.Right && IsDropAllowed(obj, location, button) ) {
				this.DesignerViewControl.AddRoute((DesignerControl)obj, this);
			}
		}
		public override bool IsDropAllowed(object obj, Point location, MouseButtons button)
		{
			DesignerControl dctrl = obj as DesignerControl;
			if ( button == MouseButtons.Right ) {
				if ( obj is ServiceComponentSymbol ) {
					return ( this.Parent == dctrl.Parent );
				} else if ( obj is InterfaceSymbol ) {
					return ( dctrl.Parent != this.Parent );
				} else if ( obj is ReferenceSymbol ) {
					return ( dctrl.Parent is ServiceComponentSymbol && dctrl.Parent.Parent == this.Parent );
				} else {
					return this.IsDropAllowed(obj.GetType(), location, button);
				}
			} else {
				return this.IsDropAllowed(obj.GetType(), location, button);
			}
		}
		public override bool IsDropAllowed(Type type, Point location, MouseButtons button)
		{
			if ( button == MouseButtons.Right ) {
				if ( type == typeof(InterfaceSymbol) ||
					 type == typeof(ReferenceSymbol) ||
					 type == typeof(ServiceComponentSymbol) ||
					 type == typeof(Generic.MappingSymbol) ||
					 type == typeof(Generic.ExternalSymbol) )
					return true;
				else
					return false;
			} else {
				return false;
			}
		}

		public override Point GetRouteStart(RouteDockDirection dock, Route route)
		{
			if ( !_lstRoutes.Contains(route) ) {
				route.Removing += new System.ComponentModel.CancelEventHandler(route_Removing);
				_lstRoutes.Add(route);
			}
			Point pt = base.GetRouteStart(dock, route);
			if ( dock == RouteDockDirection.Left )
				pt.X += (int)( this.Width * .2 );

			return pt;
		}

		public override Point GetRouteEnd(RouteDockDirection dock, Route route)
		{
			if ( !_lstRoutes.Contains(route) ) {
				route.Removing += new System.ComponentModel.CancelEventHandler(route_Removing);
				_lstRoutes.Add(route);
			}
			Point pt = base.GetRouteEnd(dock, route);
			if ( dock == RouteDockDirection.Left )
				pt.X += (int)( this.Width * .2 );
			return pt;
		}

		public override bool CreateRouteStart(DesignerControl controlEnd, out IConnector connector,
			out LineCap cap, out CustomLineCap customcap, out RouteDockDirection dockStart,
			out RouteDockDirection dockEnd, out bool useStartConnectorAsRouteStart)
		{
			bool ok = base.CreateRouteStart(controlEnd, out connector, out cap, out customcap, out dockStart,
				out dockEnd, out useStartConnectorAsRouteStart);
			InterfaceSymbol isym = controlEnd as InterfaceSymbol;
			ReferenceSymbol rsym = controlEnd as ReferenceSymbol;
			CapabilitySymbol csym = controlEnd as CapabilitySymbol;
			if ( isym != null ) {
				//_interface = (InterfaceSymbol)controlEnd;
				//_reference = null;
				isym.OperationsChanged += new EventHandler(isym_OperationsChanged);
				isym.Removed += new EventHandler(isym_Removed);
				_lstReferenceOperations.AddRange(isym.Operations);
			} else if ( this.Parent is ServiceComponentSymbol && rsym != null ) {
				//_reference = (ReferenceSymbol)controlEnd;
				//_interface = null;
				rsym.OperationsChanged += new EventHandler(rsym_OperationsChanged);
				rsym.Removed += new EventHandler(rsym_Removed);
				_lstReferenceOperations.AddRange(rsym.Operations);
			} else if ( csym != null ) {
				if ( csym.Operation != null )
					_lstReferenceOperations.Add(csym.Operation);
			}

			dockStart = RouteDockDirection.Right;
			dockEnd = RouteDockDirection.Left;

			cap = LineCap.RoundAnchor;
			customcap = null;

			return ok;
		}

		public override bool CreateRouteEnd(DesignerControl controlStart, out IConnector connector,
			out LineCap cap, out CustomLineCap customcap, out RouteDockDirection dockStart,
			out RouteDockDirection dockEnd, out bool useEndConnectorAsRouteEnd)
		{
			bool ok = base.CreateRouteEnd(controlStart, out connector, out cap, out customcap, out dockStart,
				out dockEnd, out useEndConnectorAsRouteEnd);
			InterfaceSymbol isym = controlStart as InterfaceSymbol;
			if ( isym != null ) {
				//this.Interface = (InterfaceSymbol)controlStart;
				//_lstReferenceOperations.Clear();
				isym.OperationsChanged += new EventHandler(isym_OperationsChanged);
				isym.Removed += new EventHandler(isym_Removed);
				_lstReferenceOperations.AddRange(isym.Operations);
			}
			//if ( _connectorInterface == null && !(controlStart is ExportSymbol) ) {
			//    _connectorInterface = new InterfaceConnectorSymbol();
			//    _connectorInterface.Location = new Point(-(int)( _connectorInterface.Width / 2 ) - 5, (int)( this.ClientRectangle.Height / 2 )-(_connectorInterface.Height)+4 );
			//    _connectorInterface.Anchor = System.Windows.Forms.AnchorStyles.Left;
			//    this.Controls.Add(_connectorInterface);
			//}

			if ( controlStart is InterfaceSymbol ) {
				connector = this;
				dockEnd = RouteDockDirection.Right;
				dockStart = RouteDockDirection.Left;
				cap = LineCap.RoundAnchor;
				customcap = null;
				//cap = LineCap.Custom;
				//customcap = new AdjustableArrowCap(7.0f, 10.0f, false);
			} else {
				//connector = _connectorInterface;
				cap = LineCap.RoundAnchor;
				customcap = null;
				dockStart = RouteDockDirection.Right;
				dockEnd = RouteDockDirection.Left;
			}
			return ok;
		}

		public override void ReadXml(System.Xml.XmlReader reader)
		{
			RepositoryService repSvc = (RepositoryService)this.GetService(typeof(RepositoryService));
			if ( repSvc == null )
				throw new NullReferenceException("RepositoryService not available.");

			System.ComponentModel.BooleanConverter bc = new System.ComponentModel.BooleanConverter();
			while ( reader.Read() ) {
				switch ( reader.Name ) {
					case "DesignerControl":
						if ( reader.NodeType == System.Xml.XmlNodeType.EndElement )
							return;
						break;
					case "IsCollapsed":
						bool.TryParse(reader.ReadString(), out _isCollapsed);
						if ( _isCollapsed )
							Collapse();
						break;
					case "GenericFolder":
						if ( reader.MoveToAttribute("id") && reader.ReadAttributeValue() )
							this.RepositoryItem = repSvc.GetItem(ItemType.GenericFolder, int.Parse(reader.Value), false);
						if ( reader.MoveToAttribute("isRef") && reader.ReadAttributeValue() )
							this.IsReference = (bool)bc.ConvertFromString(reader.Value);
						break;
					default:
						ReadStandardProperties(reader);
						break;
				}
			}
		}
		public override void WriteXml(System.Xml.XmlWriter writer)
		{
			System.ComponentModel.BooleanConverter bc = new System.ComponentModel.BooleanConverter();
			WriteStandardProperties(writer);

			writer.WriteElementString("IsCollapsed", _isCollapsed.ToString());

			if ( _folder != null ) {
				writer.WriteStartElement("GenericFolder");
				writer.WriteAttributeString("id", _folder.ID.ToString());
				writer.WriteAttributeString("name", _folder.Name);
				writer.WriteAttributeString("isRef", bc.ConvertToString(this.IsReference));
				writer.WriteEndElement();
			}
		}
		#endregion

		#endregion

		#region Protected Members

		#region Overrides
		protected override void CalculateBorder(int width, int height, ref GraphicsPath path)
		{
			// NOT USED
			//             x1
			//             |\
			//	y1	-------- \
			//  y2__|_ _ _ _ _\
			//      |         /
			//  y3  -------- /
			//             |/
			int y1 = (int)( height * .25 );
			int y2 = (int)( height * .5 );
			int y3 = (int)( height * .75 );
			int x1 = (int)( width * .75 );
			path.AddPolygon(
				new Point[] {
					new Point(0, y1),
					new Point(x1, y1),
					new Point(x1, 0),
					new Point(width, y2),
					new Point(x1, height),
					new Point(x1, y3),
					new Point(0, y3)
				}
			);
		}
		protected override Rectangle CalculateClientArea()
		{
			//    x<--w->|
			//	__|_____ |
			//	\ |     \|__y
			//	 \|cacaca\ ^
			//	 / cacaca/_h
			//	/_______/
			//	
			Rectangle rc = this.Bounds;
			int pad = 5;
			int x = rc.X + (int)( rc.Width * .25 );
			int w = (int)( ( rc.Width * .75 ) - ( pad * 2 ) );
			int y = rc.Y + (int)( rc.Height * .25 ) + pad;
			int h = (int)( ( rc.Height * .75 ) - ( pad * 2 ) );
			return new Rectangle(x, y, w, h);
		}
		protected override void OnVisibleChanged()
		{
			if ( !this._isCollapsed )
				base.OnVisibleChanged();
		}
		#endregion

		#endregion

		#region Private Members

		#region Variables
		private bool _isCollapsed;

		private List<Repository.Operation> _lstReferenceOperations;
		private List<Route> _lstRoutes;

		private InterfaceSymbol _interface;
		private ReferenceSymbol _reference;
		#endregion

		#region Methods
		private void onOperationsChanged()
		{
			EventHandler tmp = this.OperationsChanged;
			if ( tmp != null )
				tmp(this, EventArgs.Empty);
		}
		#endregion

		#region Event Handlers
		private void context_EditOperations(object sender, EventArgs e)
		{
			if ( this.Operations == null )
				return;
			FormOperations frm = new FormOperations(_folder);
			frm.ReadOnly = true;
			frm.FormClosed += new FormClosedEventHandler(frm_FormClosed);
			DockContent dc = this.DesignerViewControl.Parent as DockContent;
			if ( dc != null ) {
				Point loc = this.Parent.PointToDesignerView(this.Location);
				loc = this.DesignerViewControl.PointToScreen(loc);
				loc.X -= 50;
				loc.Y += this.Height + 20;
				frm.Show(this.Operations, dc.DockPanel, loc);
			} else {
				frm.Show(this.Operations);
			}
		}
		private void frm_FormClosed(object sender, FormClosedEventArgs e)
		{
			FormOperations frm = sender as FormOperations;
			if ( frm == null )
				return;
			if ( frm.DialogResult == DialogResult.OK && !frm.ReadOnly ) {
				this.Interface.Operations.Clear();
				this.Interface.Operations.AddRange(frm.Operations);
			}
			frm.FormClosed -= new FormClosedEventHandler(frm_FormClosed);
			this.DesignerViewControl.BringToFront();
		}
		private void context_Remove(object sender, EventArgs e)
		{
			this.Remove();
		}

		private void route_Removing(object sender, System.ComponentModel.CancelEventArgs e)
		{
			Route route = sender as Route;
			if ( route == null || e.Cancel )
				return;

			InterfaceSymbol isym = route.StartControl == this ?
				route.EndControl as InterfaceSymbol : route.StartControl as InterfaceSymbol;
			ReferenceSymbol rsym = route.StartControl == this ?
				route.EndControl as ReferenceSymbol : route.StartControl as ReferenceSymbol;
			CapabilitySymbol csym = route.StartControl == this ?
				route.EndControl as CapabilitySymbol : route.StartControl as CapabilitySymbol;

			if ( isym != null ) {
				foreach ( Repository.Operation op in isym.Operations ) {
					_lstReferenceOperations.Remove(op);
				}
				onOperationsChanged();
			} else if ( rsym != null ) {
				foreach ( Repository.Operation op in rsym.Operations ) {
					_lstReferenceOperations.Remove(op);
				}
				onOperationsChanged();
			} else if ( csym != null ) {
				_lstReferenceOperations.Remove(csym.Operation);
				onOperationsChanged();
			}

			route.Removing -= new System.ComponentModel.CancelEventHandler(route_Removing);
			_lstRoutes.Remove(route);
		}

		private void rsym_Removed(object sender, EventArgs e)
		{
			ReferenceSymbol rsym = sender as ReferenceSymbol;
			if ( rsym == null )
				return;
			this.Operations.Clear();
			onOperationsChanged();
		}
		private void rsym_OperationsChanged(object sender, EventArgs e)
		{
			ReferenceSymbol rsym = sender as ReferenceSymbol;
			if ( rsym == null )
				return;
			this.Operations.Clear();
			this.Operations.AddRange(rsym.Operations);
			onOperationsChanged();
		}
		private void isym_Removed(object sender, EventArgs e)
		{
			InterfaceSymbol isym = sender as InterfaceSymbol;
			if ( isym == null )
				return;
			this.Operations.Clear();
			onOperationsChanged();
		}
		private void isym_OperationsChanged(object sender, EventArgs e)
		{
			InterfaceSymbol isym = sender as InterfaceSymbol;
			if ( isym == null )
				return;
			this.Operations.Clear();
			this.Operations.AddRange(isym.Operations);
			onOperationsChanged();
		}

		#endregion

		#endregion

		#region IRepositoryItemSymbol Members

		public bool SaveHierarchy
		{
			get { return true; }
		}

		private bool _isReference = false;
		public bool IsReference
		{
			get { return _isReference; }
			set { _isReference = value; }
		}

		public bool CanBeMainControl
		{
			get { return false; }
		}

		public OpenComposite.EII.Repository.IRepositoryItem RepositoryItem
		{
			get
			{
				return _folder;
			}
			set
			{
				_folder = value as Repository.GenericFolder;
				if ( _folder != null ) {
					if ( _folder.ID > 0 && _folder.Name != Resources.sNewGenericFolder )
						this.Text = _folder.Name;
					else
						_folder.Name = this.Text;
				}
			}
		}

		public void Load(int idRepository, int idDomain)
		{
			if ( _folder != null ) {
				RepositoryService repSvc = (RepositoryService)this.GetService(typeof(RepositoryService));
				DataTable dt = Global.Data.GetRepositoryHierarchyChildRepositoryList(
									_folder, Repository.ItemType.Operation);
				_lstReferenceOperations.Clear();
				foreach ( DataRow row in dt.Rows ) {
					Repository.Operation op = repSvc.GetItem(Repository.ItemType.Operation, row) as Repository.Operation;
					if ( op != null ) {
						_lstReferenceOperations.Add(op);
					}
				}
			}
		}
		public bool Save(int idRepository, int idDomain)
		{
			if ( _folder == null ) {
				_folder = new OpenComposite.EII.Repository.GenericFolder(true);
				_folder.Name = this.Text;
			}
			_folder.ExtendedProperties.IsReferenceFolder = true;
			DesignerControl dcReferenced = null;
			if ( _interface != null ) {
				dcReferenced = _interface.Parent;
			} else if ( _reference != null && _reference.Interface != null ) {
				dcReferenced = _reference.Interface.Parent;
			}
			DesignerControl[] dcs = this.GetPredecessors();
			if ( dcs.Length > 0 ) {
				if ( dcs[0] is InterfaceSymbol )
					dcReferenced = dcs[0].Parent;
			}
			if ( dcReferenced == null ) {
				dcs = this.GetSuccessors();
				if ( dcs.Length > 0 ) {
					if ( dcs[0] is InterfaceSymbol )
						dcReferenced = dcs[0].Parent;
				}
			}
			if ( dcReferenced != null ) {
				_folder.ExtendedProperties.ReferenceName = dcReferenced.Name;
				IRepositoryItemSymbol ris = dcReferenced as IRepositoryItemSymbol;
				if ( ris != null ) {
					_folder.ExtendedProperties.ReferenceType = ris.RepositoryItem.RepositoryItemType;
					_folder.ExtendedProperties.ReferenceID = ris.RepositoryItem.ID;
				}
			}
			bool ok = _folder.Save();
			if ( ok ) {
				foreach ( Repository.Operation op in this.Operations ) {
					op.Save();
					Global.Data.AddRepositoryHierarchy(_folder, op, idRepository);
				}
			}
			return ok;
		}

		public bool Delete(bool bAsk)
		{
			if ( _folder == null )
				return true;

			return _folder.Delete(bAsk);
		}

		protected override void OnTextChanged(EventArgs e)
		{
			if ( _folder != null )
				_folder.Name = this.Text;
			base.OnTextChanged(e);
		}
		private Repository.GenericFolder _folder;


		#endregion
	}
}
